{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "b42814f0",
   "metadata": {},
   "source": [
    "# 习题\n",
    "## 习题7.2\n",
    "![image.png](./images/exercise2_1.png)\n",
    "### sklearn.svm.SVC\n",
    "\n",
    "*(C=1.0, kernel='rbf', degree=3, gamma='auto', coef0=0.0, shrinking=True, probability=False,tol=0.001, cache_size=200, class_weight=None, verbose=False, max_iter=-1, decision_function_shape=None,random_state=None)*\n",
    "\n",
    "参数：\n",
    "\n",
    "- C：C-SVC的惩罚参数C?默认值是1.0\n",
    "\n",
    "C越大，相当于惩罚松弛变量，希望松弛变量接近0，即对误分类的惩罚增大，趋向于对训练集全分对的情况，这样对训练集测试时准确率很高，但泛化能力弱。C值小，对误分类的惩罚减小，允许容错，将他们当成噪声点，泛化能力较强。\n",
    "\n",
    "- kernel ：核函数，默认是rbf，可以是‘linear’, ‘poly’, ‘rbf’, ‘sigmoid’, ‘precomputed’ \n",
    "    \n",
    "    – 线性：u'v\n",
    "    \n",
    "    – 多项式：(gamma*u'*v + coef0)^degree\n",
    "\n",
    "    – RBF函数：exp(-gamma|u-v|^2)\n",
    "\n",
    "    – sigmoid：tanh(gamma*u'*v + coef0)\n",
    "\n",
    "\n",
    "- degree ：多项式poly函数的维度，默认是3，选择其他核函数时会被忽略。\n",
    "\n",
    "\n",
    "- gamma ： ‘rbf’,‘poly’ 和‘sigmoid’的核函数参数。默认是’auto’，则会选择1/n_features\n",
    "\n",
    "\n",
    "- coef0 ：核函数的常数项。对于‘poly’和 ‘sigmoid’有用。\n",
    "\n",
    "\n",
    "- probability ：是否采用概率估计？.默认为False\n",
    "\n",
    "\n",
    "- shrinking ：是否采用shrinking heuristic方法，默认为true\n",
    "\n",
    "\n",
    "- tol ：停止训练的误差值大小，默认为1e-3\n",
    "\n",
    "\n",
    "- cache_size ：核函数cache缓存大小，默认为200\n",
    "\n",
    "\n",
    "- class_weight ：类别的权重，字典形式传递。设置第几类的参数C为weight*C(C-SVC中的C)\n",
    "\n",
    "\n",
    "- verbose ：允许冗余输出？\n",
    "\n",
    "\n",
    "- max_iter ：最大迭代次数。-1为无限制。\n",
    "\n",
    "\n",
    "- decision_function_shape ：‘ovo’, ‘ovr’ or None, default=None3\n",
    "\n",
    "\n",
    "- random_state ：数据洗牌时的种子值，int值\n",
    "\n",
    "\n",
    "主要调节的参数有：C、kernel、degree、gamma、coef0。\n",
    "\n",
    "下面是一个简单的例子，展示了如何使用SVC：\n",
    "\n",
    "```python\n",
    "from sklearn.svm import SVC\n",
    "from sklearn.datasets import load_iris\n",
    "from sklearn.model_selection import train_test_split\n",
    "\n",
    "# 加载数据集\n",
    "iris = load_iris()\n",
    "X, y = iris.data, iris.target\n",
    "\n",
    "# 划分训练集和测试集\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)\n",
    "\n",
    "# 创建SVC对象，使用RBF核\n",
    "svc = SVC(kernel='rbf', C=1.0, gamma='auto')\n",
    "\n",
    "# 训练模型\n",
    "svc.fit(X_train, y_train)\n",
    "\n",
    "# 进行预测\n",
    "predictions = svc.predict(X_test)\n",
    "\n",
    "# 评估模型\n",
    "accuracy = svc.score(X_test, y_test)\n",
    "print(f\"Accuracy: {accuracy:.2f}\")\n",
    "```\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "fa9cb313",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "权值向量w =  [[-1.  2.]]\n",
      "偏置b =  [-2.]\n",
      "support vectors = [[3. 2.]\n",
      " [1. 2.]\n",
      " [3. 3.]]\n"
     ]
    }
   ],
   "source": [
    "%matplotlib inline\n",
    "from sklearn.svm import SVC\n",
    "\n",
    "# 加载数据\n",
    "X = [[1, 2], [2, 3], [3, 3], [2, 1], [3, 2]]\n",
    "y = [1, 1, 1, -1, -1]\n",
    "\n",
    "# 训练SVM模型\n",
    "clf = SVC(kernel='linear', C=10000)\n",
    "clf.fit(X, y)\n",
    "\n",
    "# 得到w、b和支持向量\n",
    "print(\"权值向量w = \", clf.coef_)\n",
    "print(\"偏置b = \", clf.intercept_)\n",
    "print(\"support vectors =\", clf.support_vectors_)\n"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "926e7356",
   "metadata": {},
   "source": [
    "![image.png](./images/exercise2_2.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "dcf78f6f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "# 绘制数据点\n",
    "color_seq = ['red' if v==1 else 'blue' for v in y]\n",
    "plt.scatter([i[0] for i in X], [i[1] for i in X], c=color_seq)\n",
    "\n",
    "# 得到x轴的所有点\n",
    "xaxis = np.linspace(0, 3.5)\n",
    "w = clf.coef_[0]\n",
    "\n",
    "# 计算斜率\n",
    "a = -w[0] / w[1]\n",
    "\n",
    "# 得到分离超平面\n",
    "y_sep = a * xaxis - (clf.intercept_[0]) / w[1]\n",
    "\n",
    "# 下边界超平面\n",
    "b = clf.support_vectors_[0]\n",
    "yy_down = a * xaxis + (b[1] - a * b[0])\n",
    "\n",
    "# 上边界超平面\n",
    "b = clf.support_vectors_[-1]\n",
    "yy_up = a * xaxis + (b[1] - a * b[0])\n",
    "\n",
    "# 绘制超平面\n",
    "# 黑色实线\n",
    "plt.plot(xaxis, y_sep, 'k-')\n",
    "# 黑色虚线\n",
    "plt.plot(xaxis, yy_down, 'k--')\n",
    "plt.plot(xaxis, yy_up, 'k--')\n",
    "\n",
    "# 绘制支持向量\n",
    "plt.xlabel('$x^{(1)}$')\n",
    "plt.ylabel('$x^{(2)}$')\n",
    "plt.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], \n",
    "            s=150, facecolors='none', edgecolors='k')\n",
    "\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5af49f6d",
   "metadata": {},
   "source": "# 非线性支持向量机代码实现"
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "7378e152",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<matplotlib.legend.Legend at 0x30c75b150>"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "from sklearn.datasets import load_iris\n",
    "from sklearn.model_selection import  train_test_split\n",
    "import matplotlib.pyplot as plt\n",
    "%matplotlib inline\n",
    "\n",
    "# data\n",
    "def create_data():\n",
    "    iris = load_iris()\n",
    "    df = pd.DataFrame(iris.data, columns=iris.feature_names)\n",
    "    df['label'] = iris.target\n",
    "    df.columns = [\n",
    "        'sepal length', 'sepal width', 'petal length', 'petal width', 'label'\n",
    "    ]\n",
    "    data = np.array(df.iloc[:100, [0, 1, -1]])\n",
    "    for i in range(len(data)):\n",
    "        if data[i, -1] == 0:\n",
    "            data[i, -1] = -1\n",
    "    # print(data)\n",
    "    return data[:, :2], data[:, -1]\n",
    "\n",
    "X, y = create_data()\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.25)\n",
    "\n",
    "plt.scatter(X[:50,0],X[:50,1], label='0')\n",
    "plt.scatter(X[50:,0],X[50:,1], label='1')\n",
    "plt.legend()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "478409dd",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The accuracy used SVM to predict is 88.00\n"
     ]
    }
   ],
   "source": [
    "class SVM:\n",
    "    def __init__(self, max_iter=100, kernel='linear'):\n",
    "        self.max_iter = max_iter\n",
    "        self._kernel = kernel\n",
    "\n",
    "    def init_args(self, features, labels):\n",
    "        self.m, self.n = features.shape\n",
    "        self.X = features\n",
    "        self.Y = labels\n",
    "        self.b = 0.0\n",
    "\n",
    "        # 将Ei保存在一个列表里\n",
    "        # 拉格朗日乘子\n",
    "        self.alpha = np.ones(self.m)\n",
    "        # 每个样本的误差项，初始化为每个样本的预测值与真实值的差。\n",
    "        self.E = [self._E(i) for i in range(self.m)]\n",
    "        # 松弛变量\n",
    "        self.C = 1.0\n",
    "\n",
    "    # 判断样本是否满腹KKT条件\n",
    "    def _KKT(self, i):\n",
    "        y_g = self._g(i) * self.Y[i]\n",
    "        if self.alpha[i] == 0:\n",
    "            return y_g >= 1\n",
    "        elif 0 < self.alpha[i] < self.C:\n",
    "            return y_g == 1\n",
    "        else:\n",
    "            return y_g <= 1\n",
    "\n",
    "    # g(x)预测值，输入xi（X[i]）\n",
    "    def _g(self, i):\n",
    "        r = self.b\n",
    "        for j in range(self.m):\n",
    "            r += self.alpha[j] * self.Y[j] * self.kernel(self.X[i], self.X[j])\n",
    "        return r\n",
    "\n",
    "    # 核函数\n",
    "    def kernel(self, x1, x2):\n",
    "        if self._kernel == 'linear':\n",
    "            # 求内积\n",
    "            return sum([x1[k] * x2[k] for k in range(self.n)])\n",
    "        elif self._kernel == 'poly':\n",
    "            return (sum([x1[k] * x2[k] for k in range(self.n)]) + 1)**2\n",
    "\n",
    "        return 0\n",
    "\n",
    "    # E（x）为g(x)对输入x的预测值和y的差\n",
    "    def _E(self, i):\n",
    "        return self._g(i) - self.Y[i]\n",
    "\n",
    "    # 选择需要迭代的alpha1和alpha2\n",
    "    def _init_alpha(self):\n",
    "        # 外层循环首先遍历所有满足0<a<C的样本点，检验是否满足KKT\n",
    "        index_list = [i for i in range(self.m) if 0 < self.alpha[i] < self.C]\n",
    "        # 否则遍历整个训练集\n",
    "        non_satisfy_list = [i for i in range(self.m) if i not in index_list]\n",
    "        # 将non_satisfy_list添加到index_list数组的末尾\n",
    "        index_list.extend(non_satisfy_list)\n",
    "\n",
    "        for i in index_list:\n",
    "            if self._KKT(i):\n",
    "                continue\n",
    "\n",
    "            # 不满足KKT条件的样本\n",
    "            E1 = self.E[i]\n",
    "            # 如果E1是+，选择最小的；如果E1是负的，选择最大的\n",
    "            if E1 >= 0:\n",
    "                j = min(range(self.m), key=lambda x: self.E[x])\n",
    "            else:\n",
    "                j = max(range(self.m), key=lambda x: self.E[x])\n",
    "            return i, j\n",
    "\n",
    "    # 根据alpha的约束条件对alpha进行剪辑\n",
    "    def _compare(self, _alpha, L, H):\n",
    "        if _alpha > H:\n",
    "            return H\n",
    "        elif _alpha < L:\n",
    "            return L\n",
    "        else:\n",
    "            return _alpha\n",
    "\n",
    "    \n",
    "    def fit(self, features, labels):\n",
    "        self.init_args(features, labels)\n",
    "\n",
    "        for t in range(self.max_iter):\n",
    "            # train，选取需要优化的alpha1和alpha2\n",
    "            i1, i2 = self._init_alpha()\n",
    "\n",
    "            # 边界，计算约束条件的上下界\n",
    "            if self.Y[i1] == self.Y[i2]:\n",
    "                L = max(0, self.alpha[i1] + self.alpha[i2] - self.C)\n",
    "                H = min(self.C, self.alpha[i1] + self.alpha[i2])\n",
    "            else:\n",
    "                L = max(0, self.alpha[i2] - self.alpha[i1])\n",
    "                H = min(self.C, self.C + self.alpha[i2] - self.alpha[i1])\n",
    "\n",
    "            E1 = self.E[i1]\n",
    "            E2 = self.E[i2]\n",
    "            # eta=K11+K22-2K12\n",
    "            eta = self.kernel(self.X[i1], self.X[i1]) + self.kernel(\n",
    "                self.X[i2],\n",
    "                self.X[i2]) - 2 * self.kernel(self.X[i1], self.X[i2])\n",
    "            if eta <= 0:\n",
    "                # print('eta <= 0')\n",
    "                continue\n",
    "\n",
    "            alpha2_new_unc = self.alpha[i2] + self.Y[i2] * (\n",
    "                E1 - E2) / eta  #此处有修改，根据书上应该是E1 - E2，书上130-131页\n",
    "            alpha2_new = self._compare(alpha2_new_unc, L, H)\n",
    "\n",
    "            alpha1_new = self.alpha[i1] + self.Y[i1] * self.Y[i2] * (\n",
    "                self.alpha[i2] - alpha2_new)\n",
    "\n",
    "            b1_new = -E1 - self.Y[i1] * self.kernel(self.X[i1], self.X[i1]) * (\n",
    "                alpha1_new - self.alpha[i1]) - self.Y[i2] * self.kernel(\n",
    "                    self.X[i2],\n",
    "                    self.X[i1]) * (alpha2_new - self.alpha[i2]) + self.b\n",
    "            b2_new = -E2 - self.Y[i1] * self.kernel(self.X[i1], self.X[i2]) * (\n",
    "                alpha1_new - self.alpha[i1]) - self.Y[i2] * self.kernel(\n",
    "                    self.X[i2],\n",
    "                    self.X[i2]) * (alpha2_new - self.alpha[i2]) + self.b\n",
    "\n",
    "            if 0 < alpha1_new < self.C:\n",
    "                b_new = b1_new\n",
    "            elif 0 < alpha2_new < self.C:\n",
    "                b_new = b2_new\n",
    "            else:\n",
    "                # 选择中点\n",
    "                b_new = (b1_new + b2_new) / 2\n",
    "\n",
    "            # 更新参数\n",
    "            self.alpha[i1] = alpha1_new\n",
    "            self.alpha[i2] = alpha2_new\n",
    "            self.b = b_new\n",
    "\n",
    "            self.E[i1] = self._E(i1)\n",
    "            self.E[i2] = self._E(i2)\n",
    "        return 'train done!'\n",
    "\n",
    "    def predict(self, data):\n",
    "        r = self.b\n",
    "        for i in range(self.m):\n",
    "            r += self.alpha[i] * self.Y[i] * self.kernel(data, self.X[i])\n",
    "\n",
    "        return 1 if r > 0 else -1\n",
    "\n",
    "    def score(self, X_test, y_test):\n",
    "        right_count = 0\n",
    "        for i in range(len(X_test)):\n",
    "            result = self.predict(X_test[i])\n",
    "            if result == y_test[i]:\n",
    "                right_count += 1\n",
    "        return right_count / len(X_test)\n",
    "\n",
    "    def _weight(self):\n",
    "        # linear model\n",
    "        yx = self.Y.reshape(-1, 1) * self.X\n",
    "        self.w = np.dot(yx.T, self.alpha)\n",
    "        return self.w\n",
    "    \n",
    "    \n",
    "svm = SVM(max_iter=200)\n",
    "svm.fit(X_train, y_train)\n",
    "print(f'The accuracy used SVM to predict is {svm.score(X_test, y_test)*100:.2f}')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5c739cf8",
   "metadata": {},
   "source": [
    "# scikit-learn实例"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "11dece5e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "The accuracy used sklearn.svm.SVC to predict is 96.00\n"
     ]
    }
   ],
   "source": [
    "from sklearn.svm import SVC\n",
    "clf = SVC()\n",
    "clf.fit(X_train, y_train)\n",
    "\n",
    "print(f'The accuracy used sklearn.svm.SVC to predict is {clf.score(X_test, y_test)*100:.2f}')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.5"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {},
   "toc_section_display": true,
   "toc_window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
